package cn.lingyangwl.agile.infra.weixin.mp.service.impl;

import cn.lingyangwl.agile.common.core.exception.enums.GlobalErrorEnum;
import cn.lingyangwl.agile.infra.weixin.mp.assembly.MpTagAssembly;
import cn.lingyangwl.agile.infra.weixin.mp.manager.MpTagManager;
import cn.lingyangwl.agile.infra.weixin.mp.mapper.MpTagMapper;
import cn.lingyangwl.agile.infra.weixin.mp.model.WxMpContext;
import cn.lingyangwl.agile.infra.weixin.mp.model.entity.MpTag;
import cn.lingyangwl.agile.infra.weixin.mp.model.rqrs.MpTagListReq;
import cn.lingyangwl.agile.infra.weixin.mp.model.rqrs.MpTagPageReq;
import cn.lingyangwl.agile.infra.weixin.mp.model.rqrs.MpTagReq;
import cn.lingyangwl.agile.infra.weixin.mp.handler.WxMpHandler;
import cn.lingyangwl.agile.infra.weixin.mp.service.MpTagService;
import cn.lingyangwl.agile.model.module.config.param.WxMpParam;
import cn.lingyangwl.framework.mybatis.plus.utils.PageUtil;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpUserTagService;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 公众号标签
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class MpTagServiceImpl extends ServiceImpl<MpTagMapper, MpTag>
    implements IService<MpTag>, MpTagService {

    @Resource
    private MpTagManager mpTagManager;

    @Resource
    private MpTagAssembly mpTagAssembly;
    @Resource
    private WxMpHandler wxMpHandler;
    
    /**
     * 分页查询 公众号标签
     *
     * @return 返回分页数据
     */
    @Override
    public IPage<MpTag> pageMpTag(MpTagPageReq req) {
        LocalDateTime beginTime = req.getBeginLocalDateTime();
        LocalDateTime endTime = req.getEndLocalDateTime();
        LambdaQueryWrapper<MpTag> queryWrapper = MpTag.lqw()
            .like(StringUtils.isNotEmpty(req.getName()), MpTag::getName, req.getName())
            .ge(Objects.nonNull(beginTime), MpTag::getCreatedAt, beginTime)
            .le(Objects.nonNull(endTime), MpTag::getCreatedAt, endTime)
            .orderByDesc(MpTag::getUpdatedAt);
        return this.page(PageUtil.to(req), queryWrapper);
    }

    @Override
    public List<MpTag> listMpTag(MpTagListReq query) {
        LambdaQueryWrapper<MpTag> lqm = MpTag.lqw()
                .like(StringUtils.isNotEmpty(query.getName()), MpTag::getName, query.getName())
                .orderByDesc(MpTag::getUpdatedAt);
        return this.list(lqm);
    }

    /**
     * 根据主键查询 公众号标签
     *
     * @param id 主键
     * @return 返回记录，没有返回null
     */
    @Override
    public MpTag getMpTagById(Long id) {
        return this.getById(id);
    }

    /**
     * 保存 公众号标签
     *
     * @param req 新增的记录
     * @return 返回影响行数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveMpTag(MpTagReq req) {
        try {
            WxMpParam mpParam = wxMpHandler.getContext().getMpParam();
            MpTag entity = mpTagAssembly.toMpTag(req);
            entity.setId(null);
            entity.setMpAppId(mpParam.getAppId());
            boolean ret = mpTagManager.saveMpTag(entity);
            if (ret) {
                WxMpContext context = wxMpHandler.getContext();
                WxMpUserTagService userTagService = context.getService().getUserTagService();
                WxUserTag wxUserTag = userTagService.tagCreate(req.getName());
                entity.setTagId(wxUserTag.getId());
                entity.setCount(wxUserTag.getCount());
                this.updateById(entity);
            }
            return ret;
        } catch (WxErrorException e) {
            log.error("wxError: {}", e.getMessage());
            throw new BizException(e.getError().getErrorMsg());
        }
    }


    /**
     * 更新 公众号标签
     *
     * @param req 修改的记录
     * @return 返回影响行数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMpTagById(MpTagReq req) {
        try {
            MpTag mpTag = this.getById(req.getId());
            if (Objects.isNull(mpTag)) {
                throw new BizException(GlobalErrorEnum.OPERATION_FAIL_SELETE);
            }

            if (MpTag.WX_SYS_TAG_ID.compareTo(mpTag.getTagId()) == 0) {
                throw new BizException("微信系统标签不能修改");
            }

            WxMpContext context = wxMpHandler.getContext();
            WxMpParam mpParam = context.getMpParam();
            MpTag entity = mpTagAssembly.toMpTag(req);
            entity.setMpAppId(mpParam.getAppId());
            boolean ret = mpTagManager.updateMpTag(entity);
            if (ret && !mpTag.getName().equals(req.getName())) {
                WxMpUserTagService userTagService = context.getService().getUserTagService();
                Boolean wxRet = userTagService.tagUpdate(mpTag.getTagId(), req.getName());
                if (!Boolean.TRUE.equals(wxRet)) {
                    throw new BizException("更新微信公众号标签失败");
                }
            }
            return ret;
        } catch (WxErrorException e) {
            log.error("wxError: {}", e.getMessage());
            throw new BizException(e.getError().getErrorMsg());
        }
    }

    /**
     * 通过id删除 公众号标签
     *
     * @param id 删除的主键
     * @return 返回影响行数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMpTagById(Long id) {
        MpTag mpTag = this.getById(id);
        if (Objects.isNull(mpTag)) {
            return true;
        }

        if (MpTag.WX_SYS_TAG_ID.compareTo(mpTag.getTagId()) == 0) {
            throw new BizException("微信系统标签不能为删除");
        }

        boolean ret = this.removeById(id);
        try {
            if (ret) {
                WxMpContext context = wxMpHandler.getContext();
                WxMpUserTagService userTagService = context.getService().getUserTagService();
                Boolean wxRet = userTagService.tagDelete(mpTag.getTagId());
                if (!Boolean.TRUE.equals(wxRet)) {
                    throw new BizException("删除微信公众号标签失败");
                }
            }
        } catch (WxErrorException e) {
            log.error("wxError: {}", e.getMessage());
            throw new BizException(e.getError().getErrorMsg());
        }
        return ret;
    }

    @Override
    public void syncMpTag() {
        Map<Long, MpTag> mpTagMap = this.list().stream().collect(Collectors.toMap(MpTag::getTagId, Function.identity()));
        try {
            WxMpContext context = wxMpHandler.getContext();
            WxMpUserTagService userTagService = context.getService().getUserTagService();
            List<WxUserTag> wxUserTags = userTagService.tagGet();
            List<MpTag> syncTag = new ArrayList<>();
            wxUserTags.forEach(e -> {
                MpTag mpTag = new MpTag();
                mpTag.setTagId(e.getId());
                mpTag.setMpAppId(context.getMpParam().getAppId());
                mpTag.setCount(e.getCount());
                mpTag.setName(e.getName());

                MpTag record = mpTagMap.get(e.getId());
                if (Objects.isNull(record)) {
                    this.save(mpTag);
                    return;
                }

                mpTag.setId(record.getTagId());
                syncTag.add(mpTag);
            });

            this.updateBatchById(syncTag);
        } catch (WxErrorException e) {
            log.error("wxError: {}", e.getMessage());
            throw new BizException(e.getError().getErrorMsg());
        }
    }
}
